using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Collections;
using NovodexWrapper;

namespace marbletrack
{
    public class Ball
    {
        private ModelClass model_;
        public Matrix transform_;
        private float ballDensity;
        private float ballRadius;
        public NxActor ballActor_;
        private Physics physics;
        public Ship ship_ = null;
        public Vector3 startingPosition = Game1.StartingPosition + new Vector3(0, Game1.SQUARESIZE * 2f, Game1.SQUARESIZE);

        public Ball()
        {
            //Initialize all the balls variables with default position
            SetupVariables(Game1.StartingPosition + new Vector3(0, Game1.SQUARESIZE,Game1.SQUARESIZE));

            model_.FlagTextured = true;
            //model_.LoadTexture(Game1.redwhite);
        }
        private void SetupVariables(Vector3 position)
        {
            model_ = Game1.BallModel;
            physics = Game1.GetPhysics;
            ballDensity = 52;
            ballRadius = 65f;
            transform_ = Matrix.Identity;
            transform_.Translation = position;

            //Create ball actor from descriptors
            NxShapeDesc ballShapeDesc = new NxSphereShapeDesc(NxMat34.Identity, NxShapeFlag.USE_DEFAULT, 0, physics.BallMaterial.getMaterialIndex(), "marble", ballRadius);
            NxBodyDesc ballBodyDesc = new NxBodyDesc();
            NxActorDesc ballActorDesc = new NxActorDesc(ballShapeDesc, ballBodyDesc, ballDensity, MathConversion.ToNxMat34(transform_));
            ballActor_ = physics.PhysicsScene.createActor(ballActorDesc);

            ballActor_.UserData = (IntPtr)0;
            //Add to ball actor group
            ballActor_.setGroup(Physics.BALL_PHYSICS_GROUP);

            //Set AngularDamping so the ball dosen't keep rolling forever
            ballActor_.AngularDamping = 1f;

            //Increases balls max angular velocity so it will roll down the track properly
            ballActor_.setMaxAngularVelocity(150);

            #region Convex Mesh Experiment
            //NxVec3[] vertexBuffer = MathConversion.ExtractVertexBuffer(model_.MeshVertexBuffers[0]);
            //NxCooking.InitCooking();

            //NxConvexMeshDesc ballMeshDesc = new NxConvexMeshDesc();
            //ballMeshDesc.numVertices = vertexBuffer.Length;
            //unsafe { ballMeshDesc.pointStrideBytes = sizeof(NxVec3); }
            //ballMeshDesc.setPoints(vertexBuffer, false);
            //ballMeshDesc.FlagComputeConvex = true;

            //NovodexMemoryStream buf = new NovodexMemoryStream();
            //NxCooking.CookConvexMesh(ballMeshDesc, buf);

            //NxCooking.CloseCooking();

            //NxConvexMesh ballConvexMesh = physics.PhysicsSDK.createConvexMesh(buf);

            //NxBodyDesc ballBodyDesc = new NxBodyDesc();
            //NxConvexShapeDesc ballConvexShapeDesc = new NxConvexShapeDesc();
            //NxActorDesc ballActorDesc = new NxActorDesc();
            //ballConvexShapeDesc.MeshData = ballConvexMesh;
            //ballBodyDesc.angularDamping = 0.5f;
            //ballActorDesc.addShapeDesc(ballConvexShapeDesc);
            //ballActorDesc.BodyDesc = ballBodyDesc;
            //ballActorDesc.density = ballDensity;

            //ballActor_ = physics.PhysicsScene.createActor(ballActorDesc);
            #endregion
        }
       
        public Vector3 Position
        {
            get
            {
                return transform_.Translation;
            }
            set
            {
                ballActor_.setLinearVelocity(NxVec3.Zero);
                ballActor_.setGlobalPosition(MathConversion.ToNxVec3(value));
            }
        }

        public Vector3 Velocity
        {
            get
            {
                    return (MathConversion.ToVector3(this.ballActor_.getLinearVelocity()));
            }
        }

        // Ticks the physics simulation and assigns the transform matrix to the new calculated value
        public void Update()
        {
            transform_ = MathConversion.ToMatrix(ballActor_.getGlobalPose());
        }

        // Draw the ball using calculated transform matrix
        public void Draw()
        {
            model_.Draw(transform_);
        }
    }
}
